﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using Go;
using HalconDotNet;

namespace fhs
{
    public partial class VisionDebugForm : Form
    {
        static public VisionDebugForm obj;
        internal CameraControl CameraView;
        internal CameraControl[] ObjectsPreview;
        HObject _lastOpenImage;
        HObject _topImage;
        generator _action;
        chan<bool> _refChan;
        chan<void_type> _snapChan;
        chan<void_type> _refViewChan;
        csp_chan<void_type, void_type> _stopSnap;

        public VisionDebugForm()
        {
            obj = this;
            InitializeComponent();
        }

        private void CameraDebugForm_Load(object sender, EventArgs e)
        {
            CameraView = new CameraControl();
            CameraView.HighMode = true;
            CameraView.Anchor = AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Left | AnchorStyles.Bottom;
            CameraView.Size = panel_Camera.Size;
            CameraView.Title = "Main";
            CameraView.Text = "Main";
            panel_Camera.Controls.Add(CameraView);
            CameraView.MouseMove += new MouseEventHandler(this.CameraViewMouseMoveEvent);
            ObjectsPreview = new CameraControl[tableLayoutPanel_preview.RowCount];
            for (int i = 0; i < tableLayoutPanel_preview.RowCount; i++)
            {
                CameraControl preview = new CameraControl();
                ObjectsPreview[i] = preview;
                preview.EnableZoom(false);
                preview.MainColor = Color.White;
                PictureBox pbox = new PictureBox();
                pbox.BackColor = Color.White;
                pbox.SizeMode = PictureBoxSizeMode.AutoSize;
                pbox.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
                tableLayoutPanel_preview.Controls.Add(pbox, 1, i);
                int idx = i;
                generator.go(GlobalData.mainStrand, async delegate ()
                {
                    await generator.sleep(mt19937.global.Next(0, 100));
                    while (true)
                    {
                        await generator.sleep(100);
                        pbox.BackColor = preview.MainColor;
                    }
                });
                preview.HMouseUp += delegate (object sender1, HMouseEventArgs e1)
                {
                    if (e1.Button == MouseButtons.Right)
                    {
                        ColorDialog colDlg = new ColorDialog();
                        colDlg.Color = preview.MainColor;
                        colDlg.ShowDialog();
                        pbox.BackColor = colDlg.Color;
                        preview.MainColor = colDlg.Color;
                        preview.ShowImage();
                        CameraView.UpdateObject(preview.MainObj, preview.Margin, colDlg.Color, preview.MainObj);
                        CameraView.ShowImage();
                        return;
                    }
                    if (null != preview.MainObj)
                    {
                        _topImage = preview.MainObj;
                        if (0 == idx)
                        {
                            CameraView.Reset();
                            CameraView.Text = preview.Text;
                            CameraView.ShowImage(preview.MainColor, preview.MainObj);
                        }
                        else
                        {
                            CameraView.Text = preview.Text;
                            CameraView.AddObject(preview.Text, preview.Margin, preview.MainColor, preview.MainObj);
                            CameraView.ShowImage();
                        }
                    }
                };
                tableLayoutPanel_preview.Controls.Add(preview, 0, i);
            }
            _refChan = chan<bool>.make(GlobalData.mainStrand, 1);
            _snapChan = chan<void_type>.make(GlobalData.mainStrand, 0);
            _refViewChan = chan<void_type>.make(GlobalData.mainStrand, 0);
            _stopSnap = new csp_chan<void_type, void_type>(GlobalData.mainStrand);
            _action = generator.tgo(GlobalData.mainStrand, RefreshCameraView);
            ProductMgr.productChangeEvent.AddLast((string _) => ReLoad());
            ReLoad();
        }

        public void ReLoad()
        {
            comboBoxVision.Items.Clear();
            panel_EditForm.Controls.Clear();
            foreach (var item in VisionMgr.visions)
            {
                comboBoxVision.Items.Add(item.Value.Name);
            }
            foreach (var item in VisionMgr.visionForms)
            {
                panel_EditForm.Controls.Add(item.Value);
            }
            if (0 != comboBoxVision.Items.Count)
            {
                comboBoxVision.SelectedIndex = 0;
            }
            hScrollBar_Params.Value = 0;
            vScrollBar_Params.Value = 0;
        }

        private void CameraViewMouseMoveEvent(object sender, MouseEventArgs e)
        {
            if (null == CameraView.MainObj)
            {
                return;
            }
            try
            {
                MyPoint coord = CameraView.CoordImageCoord;
                int row = (int)Math.Floor(coord.Row);
                int col = (int)Math.Floor(coord.Col);
                HTuple Gray;
                HOperatorSet.GetGrayval(CameraView.MainObj, row, col, out Gray);
                textBox_ImageGray.Text = $"R:{row},C:{col},G:{Gray}";
            }
            catch (Exception)
            {
                textBox_ImageGray.Clear();
            }
        }

        private async Task RefreshCameraView()
        {
            async_timer timer = new async_timer();
            await generator.select().case_receive(_snapChan, async delegate ()
            {
                if (Visible)
                {
                    try
                    {
                        VisionName.Vision visionName = StringToEnum.Convert<VisionName.Vision>(comboBoxVision.Text);
                        VisionMgr.visions[visionName].ProductTime = DateTime.Now;
                        CameraView.Text = "Main";
                        await VisionMgr.visions[visionName].Preview(CameraView, ObjectsPreview, VisionMgr.visionParams[visionName]);
                        _lastOpenImage = CameraView.MainObj;
                        _topImage = CameraView.TopImage;
                    }
                    catch (generator.stop_exception) { throw; }
                    catch (Exception ec)
                    {
                        LogMgr.Error($"未处理的视觉错误 {ec.Message}");
                        timer.cancel();
                        await generator.chan_clear(_snapChan);
                    }
                }
                else
                {
                    timer.cancel();
                    await generator.chan_clear(_snapChan);
                }
            }).case_receive(_refViewChan, async delegate()
            {
                if (Visible)
                {
                    try
                    {
                        VisionName.Vision visionName = StringToEnum.Convert<VisionName.Vision>(comboBoxVision.Text);
                        VisionMgr.visions[visionName].ProductTime = DateTime.Now;
                        CameraView.Text = "Main";
                        await VisionMgr.visions[visionName].RefPriview(CameraView, ObjectsPreview, new HObject[] { _lastOpenImage }, VisionMgr.visionParams[visionName]);
                        _topImage = CameraView.TopImage;
                    }
                    catch (generator.stop_exception) { throw; }
                    catch (Exception ec)
                    {
                        LogMgr.Error($"未处理的视觉错误 {ec.Message}");
                        timer.cancel();
                        await generator.chan_clear(_snapChan);
                    }
                }
                else
                {
                    timer.cancel();
                    await generator.chan_clear(_snapChan);
                }
            }).case_receive(_refChan, delegate (bool snap)
            {
                if (snap)
                {
                    timer.cancel();
                    timer.interval(30, _snapChan.wrap_try_default());
                    return generator.non_async();
                }
                else
                {
                    timer.cancel();
                    return generator.chan_clear(_snapChan);
                }
            }).case_receive(_stopSnap, delegate ()
            {
                timer.cancel();
                return generator.chan_clear(_snapChan);
            }).loop();
        }

        private void button_real_Click(object sender, EventArgs e)
        {
            _refChan.try_post(true);
        }

        private void button_stop_Click(object sender, EventArgs e)
        {
            _refChan.post(false);
        }

        private void button_snap_Click(object sender, EventArgs e)
        {
            _snapChan.try_post(default(void_type));
        }

        private void button_save_Click(object sender, EventArgs e)
        {
            VisionMgr.Save(StringToEnum.Convert<VisionName.Vision>(comboBoxVision.Text));
        }

        private void button_saveAll_Click(object sender, EventArgs e)
        {
            VisionMgr.Save();
        }

        bool isSnap = false;
        private void button_saveDump_Click(object sender, EventArgs e)
        {
            if (isSnap)
            {
                MessageBox.Show("截图过于频繁");
                return;
            }
            isSnap = true;
            try
            {
                HalconDotNet.HObject dumpImage;
                HalconDotNet.HOperatorSet.DumpWindowImage(out dumpImage, CameraView.HalconWindow);
                HalconDotNet.HObject topImage = _topImage;
                VisionName.Vision selectVision = StringToEnum.Convert<VisionName.Vision>(comboBoxVision.Text);
                Task.Run(delegate ()
                {
                    try
                    {
                        string imageRoot = VisionBase.ImagePath;
                        DateTime date = DateTime.Now;
                        string path = $"{imageRoot}/{date.Year}年{date.Month}月{date.Day}日";
                        string dumpPath = $"{path}/{ProductMgr.currProduct}/{selectVision}/Dump";
                        Directory.CreateDirectory(dumpPath);
                        string name = $"{date.Hour}时{date.Minute}分{date.Second}秒{date.Millisecond}";
                        if (null != topImage)
                        {
                            HalconDotNet.HOperatorSet.WriteImage(topImage, "png", 0, $"{dumpPath}/{name}.png");
                        }
                        HalconDotNet.HOperatorSet.WriteImage(dumpImage, "png", 0, $"{dumpPath}/{name}_dump.png");
                    }
                    catch (Exception ec)
                    {
                        LogMgr.Error($"截图失败{ec.Message}");
                    }
                    finally
                    {
                        isSnap = false;
                    }
                });
            }
            catch (Exception ec)
            {
                LogMgr.Error($"截图失败{ec.Message}");
            }
        }

        public void RefVision()
        {
            VisionName.Vision visionName = StringToEnum.Convert<VisionName.Vision>(comboBoxVision.Text);
            VisionMgr.visions[visionName].ProductTime = DateTime.Now;
            _refViewChan.try_post(default(void_type));
        }

        private void comboBoxVision_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                string selectVision = comboBoxVision.Text;
                foreach (var item in VisionMgr.visionForms)
                {
                    item.Value.Visible = false;
                }
                Form form = VisionMgr.visionForms[StringToEnum.Convert<VisionName.Vision>(comboBoxVision.Text)];
                form.Visible = true;
                form.Location = new Point(-hScrollBar_Params.Value, -vScrollBar_Params.Value);
                RefVision();
            }
            catch (Exception ec)
            {
                MessageBox.Show(ec.Message);
            }
        }

        private void CameraDebugForm_Paint(object sender, PaintEventArgs e)
        {
            CameraView.ShowImage();
        }

        internal MyPoint DrawPoint()
        {
            try
            {
                panel_Select.Enabled = panel_EditForm.Enabled = false;
                return CameraView.DrawPoint();
            }
            finally
            {
                panel_Select.Enabled = panel_EditForm.Enabled = true;
            }
        }

        public bool DrawRectangle1(NumericUpDown Row, NumericUpDown Col, NumericUpDown Width, NumericUpDown Height)
        {
            double Row1, Col1, Row2, Col2;
            panel_Select.Enabled = panel_EditForm.Enabled = false;
            CameraView.DrawRectangle1(out Row1, out Col1, out Row2, out Col2);
            panel_Select.Enabled = panel_EditForm.Enabled = true;
            if (0 == Row1 && 0 == Col1 && 0 == Row2 && 0 == Col2)
            {
                return false;
            }
            var srcRow = Row.Value;
            var srcCol = Col.Value;
            var srcWidth = Width.Value;
            var srcHeight = Height.Value;
            try
            {
                Row.Value = (decimal)Row1;
                Col.Value = (decimal)Col1;
                Width.Value = (decimal)(Col2 - Col1 + 1);
                Height.Value = (decimal)(Row2 - Row1 + 1);
                return true;
            }
            catch (Exception)
            {
                Row.Value = srcRow;
                Col.Value = srcCol;
                Width.Value = srcWidth;
                Height.Value = srcHeight;
                return false;
            }
        }

        public bool DrawRectangle1(out double Row1, out double Col1, out double Row2, out double Col2)
        {
            panel_Select.Enabled = panel_EditForm.Enabled = false;
            CameraView.DrawRectangle1(out Row1, out Col1, out Row2, out Col2);
            panel_Select.Enabled = panel_EditForm.Enabled = true;
            if (0 == Row1 && 0 == Col1 && 0 == Row2 && 0 == Col2)
            {
                return false;
            }
            return true;
        }

        public bool DrawRectangle2(NumericUpDown Row, NumericUpDown Col, NumericUpDown Phi, NumericUpDown Len1, NumericUpDown Len2)
        {
            double row, col, phi, len1, len2;
            panel_Select.Enabled = panel_EditForm.Enabled = false;
            CameraView.DrawRectangle2(out row, out col, out phi, out len1, out len2);
            panel_Select.Enabled = panel_EditForm.Enabled = true;
            if (0 == row && 0 == col && 0 == len1 && 0 == len2)
            {
                return false;
            }
            var srcRow = Row.Value;
            var srcCol = Col.Value;
            var srcPhi = Phi.Value;
            var srcLen1 = Len1.Value;
            var srcLen2 = Len2.Value;
            try
            {
                Row.Value = (decimal)row;
                Col.Value = (decimal)col;
                Phi.Value = (decimal)FlatCalib.ToDeg(phi);
                Len1.Value = (decimal)len1;
                Len2.Value = (decimal)len2;
                return true;
            }
            catch (Exception)
            {
                Row.Value = srcRow;
                Col.Value = srcCol;
                Phi.Value = srcPhi;
                Len1.Value = srcLen1;
                Len2.Value = srcLen2;
                return false;
            }
        }

        public bool DrawRectangle2(out double Row, out double Col, out double Phi, out double Len1, out double Len2)
        {
            panel_Select.Enabled = panel_EditForm.Enabled = false;
            CameraView.DrawRectangle2(out Row, out Col, out Phi, out Len1, out Len2);
            panel_Select.Enabled = panel_EditForm.Enabled = true;
            if (0 == Row && 0 == Col && 0 == Len1 && 0 == Len2)
            {
                return false;
            }
            return true;
        }

        generator openAction = null;
        private void button_Open_Click(object sender, EventArgs e)
        {
            if (null != openAction) return;
            OpenFileDialog openImage = new OpenFileDialog();
            openImage.Multiselect = false;
            openImage.Filter = "相机图片|*.png;*.bmp";
            openImage.ShowDialog();
            if (0 != openImage.FileName.Length)
            {
                button_Open.Enabled = false;
                foreach (var view in ObjectsPreview)
                {
                    view.Clear();
                }
                CameraView.Clear();
                WaitAction.Run(out openAction, async delegate ()
                {
                    try
                    {
                        HObject ho_Image = null;
                        await generator.send_task(delegate ()
                        {
                            HOperatorSet.ReadImage(out ho_Image, openImage.FileName);
                            HOperatorSet.Rgb1ToGray(ho_Image, out ho_Image);
                        });
                        CameraView.ShowImage(ho_Image);
                        _topImage = ho_Image;
                        _lastOpenImage = ho_Image;
                        RefVision();
                    }
                    finally
                    {
                        button_Open.Enabled = true;
                        openAction = null;
                    }
                });
            }
        }

        private void vScrollBar_Preview_Scroll(object sender, ScrollEventArgs e)
        {
            tableLayoutPanel_preview.Location = new Point { X = 0, Y = -(int)((tableLayoutPanel_preview.Height - panel2.Height) * e.NewValue / vScrollBar_Preview.Maximum) };
        }

        private void hScrollBar_Params_Scroll(object sender, ScrollEventArgs e)
        {
            Form form = VisionMgr.visionForms[StringToEnum.Convert<VisionName.Vision>(comboBoxVision.Text)];
            form.Location = new Point(-e.NewValue, form.Location.Y);
        }

        private void vScrollBar_Params_Scroll(object sender, ScrollEventArgs e)
        {
            Form form = VisionMgr.visionForms[StringToEnum.Convert<VisionName.Vision>(comboBoxVision.Text)];
            form.Location = new Point(form.Location.X, -e.NewValue);
        }

        public void Clear()
        {
            CameraView.Reset();
            foreach (CameraControl pre in ObjectsPreview)
            {
                pre.Reset();
            }
        }

        public void UpdateImage(HObject image)
        {
            CameraView.ShowImage(image);
            _topImage = image;
            _lastOpenImage = image;
            RefVision();
        }

        public HObject TopImage
        {
            get
            {
                return _topImage;
            }
        }

        public HObject LastImage
        {
            get
            {
                return _lastOpenImage;
            }
        }

        public HObject NamedImage(string name)
        {
            for (int i = 0; i < ObjectsPreview.Length; i++)
            {
                if (ObjectsPreview[i].Text == name)
                {
                    return ObjectsPreview[i].MainObj;
                }
            }
            return null;
        }

        private void button_refresh_Click(object sender, EventArgs e)
        {
            RefVision();
        }
    }
}
